home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 7: Sunsite
/
Linux Cubed Series 7 - Sunsite Vol 1.iso
/
system
/
emulator
/
bsvc-1.000
/
bsvc-1
/
bsvc-1.0.4
/
src
/
Assemblers
/
hecasm
/
asm2.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-07-26
|
17KB
|
630 lines
/* asm2.c assemble a line */
/* this file contains the code to parse a line into its fields, 1 field */
/* at a time. There are two types of expressions permitted arithmetic */
/* expressions and assembly expressions. The format of arithmetic */
/* expressions is "symbol = <expression>". The format for assembly */
/* expressions is "label: opcode <modes> ;comment". Arithmetic is */
/* handled by a function called expr(). It will evaluate any arithmetic */
/* expression still in the source buffer and report any errors. */
/* The code to handle the addressing mode fields is all that need be written */
/* by a user of this assembler */
#include "asm.h"
/*
* Assemble a line.
*/
asmline()
{
static int mod, val, valid, shift, add, sh;
register struct sym *sp;
register struct sym *constant_label;
int c;
char id[NCPS];
struct d_operand src,
dst,
getmode(),
getbmode();
struct b_operand cc,
getcc();
int comma_error;
/* these are default listing types. dot->s_value is the value of the */
/* location counter. EMPTYLIS means there is no code generated on this */
/* line. This is only a default, if code is found the listmode will */
/* be changed */
listaddr = dot->s_value;
listmode = EMPTYLIS;
/* No label defined yet: */
constant_label = NULL;
loop:
/* end of line or start of comment field */
/* get a character from the source buffer */
if((c=getnb())=='\0' || c==';')
return;
/* the first character of any statement must be an alphabetic */
if(!alpha(c))
{
err('c',"illegal character");
return;
}
/* get a word from the source buffer and put it in id */
getid(c, id);
/* get next character after word and decide what to do based on that */
/*
* Direct assignment.
*/
if((c=getnb()) == '=')
{
/* lookup name on left side of =. if it has already been defined */
/* and it is not the location counter then it is a multiply defined */
/* symbol */
sp = ustlookup(id);
if((sp->s_type & S_DEF) && (sp != dot))
err('m',"multiply defined symbol");
/* evaluate the expression and put the value in the symbol pointed to */
/* by sp */
evaluate(sp);
listaddr = sp->s_value;
/* if the expression contained unresolvable symbols it is not marked as */
/* defined. If on the second pass it is still undefined then report */
/* an error */
if (pass != 0)
{
if (!(sp->s_type & S_DEF))
err('u',"undefined symbol");
/* this simple stands as a flag to tell where this symbol is defined */
sp->s_ref->r_stmtno = -sp->s_ref->r_stmtno;
}
else
sp->s_flag |= SF_ASG;
/* another listing mode for expressions */
listmode = NOCODLIS;
/* if this is not the end of the line then something is wrong */
if (((c = getnb()) != ';') && (c != '\0'))
err('x',"invalid expression");
}
/*
* Label.
*/
else
if(c == ':')
{
/* lookup the label name */
if((sp=ustlookup(id)) == dot)
err('.',"illegal use of location counter");
else
if(pass==0)
{
/* this checks to see if the label had previously been */
/* used as an arithmetic symbol */
if((sp->s_type != S_UND) && ((sp->s_flag & SF_ASG)==0))
sp->s_flag |= SF_MDF;
sp->s_type |= S_VALID;
sp->s_value = dot->s_value;
/* Could be constant definition: */
/* Save the pointer to the label: */
constant_label = sp;
}
else
{
/* same as for expressions */
if(((sp->s_flag & SF_MDF) != 0) || (sp->s_flag & SF_ASG))
err('m',"multiply defined symbol");
sp->s_type |= S_DEF;
sp->s_ref->r_stmtno = -sp->s_ref->r_stmtno;
}
/* something has been found but no code generated yet. */
/* go back and parse out the next word */
listmode = NOCODLIS;
goto loop;
}
/*
* Normal (keyword) line.
*/
else
{
/* the line is not an assignment expression, and any labels have been
* parsed out. There is still more text so it must be an opcode */
listmode = ALLLIS;
/* convert the parsed word to all lower case */
lowerconv(id);
/* put back the character that was taken out of the source buffer */
putback(c);
/* look up the word in the permanent symbol table */
if((sp = pstlookup(id)) == NULL)
{
err('o',"illegal opcode"); /* Opcode not found in the pst */
return;
}
opcode = sp->s_value;
/* all opcodes are assigned to groups so that ones with similar */
/* format can be handled identically */
switch(sp->s_type)
{
/* here is where the code must be inserted to decode the addressing modes, */
/* fill in the opcode and output the correct result. "opcode" should */
/* contain a constant portion of the actual opcode then additional */
/* information gathered from the addressing modes should be ored into */
/* base value and the output. If any routines are used in decoding the */
/* addressing modes they should be put in asm4.c. The tools you have */
/* in decoding the addressing modes are:*/
/* getnb() : get a character from the source buffer */
/* getid(c,id) : get next word, the first char was c */
/* expr() : evaluate an expression an return its value */
/* ustlookup(id) : lookup a word in the user symbol table */
/* pstlookup(id) : lookup a word in the permanent symbol table */
/* comma() : check next character to verify it is a comma */
/* the code must be written to tie these together to decode a particular */
/* set of addressing modes. Any values that need to be output can */
/* be placed in the output buffer by codew(value). */
/* these are the pseudo operations provided by this assembler. By looking */
/* at them you can get an idea how to do the opcode part */
/* START PSEUDO OPERATIONS */
case GR_LIST:
/* Turn listing on or off */
if(!pass)
break;
if((c=getnb()) == '\0' || c == ';')
break;
/* get the word after the .list directive */
getid(c,id);
/* look it up in the permanent symbol table */
/* we are looking for "on" or "off" */
if((sp = pstlookup(id)) == NULL)
{
err('u',"undefined symbol");
break;
}
else
/* check to see if it was one of the correct symbols */
if(sp->s_type != GR_ONOFF)
err('s',"improper symbol");
/* give the listing flag its value */
lflag = sp->s_value;
break;
case GR_ORG:
/* Reset origin (program location) */
/* this can also be accomplished by .=<expression> */
dot->s_value = expr();
listaddr = dot->s_value;
break;
case GR_BYTE:
/* Define next byte in memory */
do
{
/* get its value */
codew(expr());
}
while((c=getnb()) == ',');
putback(c);
break;
case GR_WORD:
/* Define next word in memory */
do
{
codew(expr());
}
while((c=getnb()) == ',');
putback(c);
break;
case GR_PASCII:
/* Packed ascii string */
ascii(0);
break;
case GR_UASCII:
/* unpaced ascii string */
ascii(1);
break;
case GR_RMW:
/* Reserve next x words in memory */
dot->s_value += expr();
listmode = NOCODLIS;
break;
case GR_RMB:
/* Reserve next x bytes in memory */
dot->s_value += expr() * 2;
listmode = NOCODLIS;
break;
case GR_RADIX:
/* set radix */
listmode = EMPTYLIS;
radix = DEC;
switch(expr())
{
case 2:
radix = BIN;
break;
case 8:
radix = OCT;
break;
case 10:
radix = DEC;
break;
case 16:
radix = HEX;
break;
default:
err('n',"bad radix format");
radix = OCT;
}
break;
/*----------------------------------------------------------------------
Constant definition:
*/
case GR_EQU: /* constant definition */
if (pass==0)
if (constant_label==NULL)
err('l',"missing label");
else
{ constant_label->s_value = expr();
constant_label = NULL;
}
else
{ while (getnb()!='\0');
goto loop;
}
break;
/*----------------------------------------------------------------------
Decode instructions:
*/
case GR_FMT1: /* dual operand */
src = getmode();
comma();
dst = getmode();
/* Error occurred during parsing of operands: */
if (src.parse_error || dst.parse_error)
/* Do nothing: skip all of the following */
break;
/* Can not have immediate mode in the destination: */
if ((dst.mode==AM_IP) && (dst.reg==15))
err('#',"illegal destination addressing mode");
/* Correct so far: proceed with coding: */
else
{ codew(opcode | (src.mode_bits<<10) | (dst.mode_bits<<8) |
(src.reg<<4) | (dst.reg));
/* Code extension word if src mode is 'immediate',
or indexed: */
if ((src.mode==AM_IP) && (src.reg==15)) /* immediate */
codew(src.ext_word);
if (src.mode==AM_IX)
{
if (src.reg==15) /* assemble as PC relative */
codew(src.ext_word - dot->s_value - 1);
else
codew(src.ext_word);
}
/* Code extension word if dst mode is indexed: */
if (dst.mode==AM_IX)
{
if (dst.reg==15) /* PC Relative */
codew(dst.ext_word - dot->s_value);
else
codew(dst.ext_word);
}
}
break;
case GR_FMT2: /* single operand */
src = getmode();
/* Error occurred during parsing of operands: */
if (src.parse_error)
/* Do nothing */
;
/* Can not have immediate mode: */
else if ((src.mode==AM_IP) && (src.reg==15))
err('#',"illegal addressing mode");
/* Correct so far: proceed with coding: */
else
{ codew(opcode | (src.mode_bits<<10) |
(src.reg<<4) | (src.reg));
/* Code extension word if src mode is indexed: */
if (src.mode==AM_IX)
if (src.reg==15) /* PC Relative */
codew(src.ext_word - dot->s_value - 1);
else
codew(src.ext_word);
}
break;
case GR_FMT3: /* bra and jsr */
comma_error = 0;
src = getbmode();
c = getnb();
/* No comma, the "branch always" condition is implied: */
if ((c==';') || (c=='\0'))
{ putback(c);
cc.parse_error = 0;
cc.mode_bits = 11;
}
else if (c==',')
cc = getcc();
else
{ err(',',"expecting comma");
comma_error = 1;
}
/* Error occurred during parsing of operands: */
if (src.parse_error || cc.parse_error || comma_error)
/* Do nothing */
;
/* Correct so far: proceed with coding: */
else
{ codew(opcode | (src.mode_bits<<10) | (src.reg<<4) |
(cc.mode_bits));
/* Code extension word if branch mode is absolute,
relative, or indexed: */
if ((src.mode==BM_A) || (src.mode==BM_I))
codew(src.ext_word);
/* If relative, have to calc. offset: */
else if (src.mode==BM_L)
codew(src.ext_word - dot->s_value - 1);
}
break;
case GR_FMT4: /* no operand */
codew(opcode);
break;
case GR_FMT5: /* push */
src = getmode();
comma();
dst = getmode();
/* Error occurred during parsing of operands: */
if (src.parse_error || dst.parse_error)
/* Do nothing */
;
/* Can only have 'register direct' in dst: */
else if (dst.mode!=AM_RD)
err('^',"illegal destination addressing mode");
/* Correct so far: proceed with coding: */
else
{ codew(opcode | (src.mode_bits<<10) |
(src.reg<<4) | (dst.reg));
/* Code extension word if src mode is 'immediate',
'absolute', or indexed: */
if (((src.mode==AM_IP) && (src.reg==15)) ||
(src.mode==AM_IX))
/* PC Relative */
/* For PC relative, an offset is calc.: */
if ((src.mode==AM_IX) && (src.reg==15))
codew(src.ext_word - dot->s_value - 1);
else
codew(src.ext_word);
}
break;
case GR_FMT6: /* exch */
src = getmode();
comma();
dst = getmode();
/* Error occurred during parsing of operands: */
if (src.parse_error || dst.parse_error)
/* Do nothing */
;
/* Can only have register direct: */
else if ((src.mode!=AM_RD) || (dst.mode!=AM_RD))
err('D',"illegal addressing mode");
/* Correct so far: proceed with coding: */
else
codew(opcode | (src.reg<<4) | (dst.reg));
break;
case GR_FMT7: /* srch */
comma_error = 0;
src = getmode();
c = getnb();
/* No comma, the "branch always" condition is implied: */
if ((c==';') || (c=='\0'))
{ putback(c);
cc.parse_error = 0;
cc.mode_bits = 11;
}
else if (c==',')
cc = getcc();
else
{ err(',',"expecting comma");
comma_error = 1;
}
/* Error occurred during parsing of operands: */
if (src.parse_error || cc.parse_error || comma_error)
/* Do nothing */
;
/* Can only have register direct: */
else if (src.mode!=AM_RD)
err('D',"illegal source addressing mode");
/* Correct so far: proceed with coding: */
else
codew(opcode | (src.reg<<4) | (cc.mode_bits));
break;
case GR_FMT8: /* move */
src = getmode();
comma();
dst = getmode();
/* Error occurred during parsing of operands: */
if (src.parse_error || dst.parse_error)
/* Do nothing: skip all of the following */
break;
/* Can not have immediate mode in the destination: */
if ((dst.mode==AM_IP) && (dst.reg==15))
err('#',"illegal destination addressing mode");
/* Correct so far: proceed with coding: */
else
{ codew(opcode | (src.mode_bits<<10) | (dst.mode_bits<<8) |
(src.reg<<4) | (dst.reg));
/* Code extension word if src mode is 'immediate',
or indexed: */
if ((src.mode==AM_IP) && (src.reg==15)) /* immediate */
codew(src.ext_word);
if (src.mode==AM_IX)
{
if (src.reg==15) /* assemble as PC relative */
{
/* reg. dir. has different PC increment */
if (dst.mode == AM_RD)
codew(src.ext_word - dot->s_value);
else
codew(src.ext_word - dot->s_value - 1);
}
else
codew(src.ext_word);
}
/* Code extension word if dst mode is indexed: */
if (dst.mode==AM_IX)
{
if (dst.reg==15) /* PC Relative */
codew(dst.ext_word - dot->s_value - 1);
else
codew(dst.ext_word);
}
}
break;
default:
err('u',"illegal instruction");
} /* end switch */
/* if there is yet more text then there is something that should not */
/* be there. */
if (((c = getnb()) != ';') && (c != '\0'))
err('X',"extra ignored");
}
}
/*
* Process the body of .pascii
* and .uascii pseudo ops.
* The z flag is true for a
* .uascii
*/
ascii(z)
int z;
{
register int c, delim, n, last;
n = 0;
/* get the delimeter to be used this may be " or ' or / etc. */
if((delim=getnb()) == '\0')
{
err('q',"unexpected end of line");
return;
}
if(!(z))
{
while((c=getmap()) != '\0' && c != delim)
{
if(++n >= 2)
{
codew(last * 256 + c);
n = 0;
}
last = c;
}
if(n == 1)
codew(last * 256);
else
codew(0);
if(c == '\0')
err('q',"unexpected end of line");
}
else
{
while((c=getmap()) != '\0' && c != delim)
codew(c);
codew(0);
if(c == '\0')
err('q',"unexpected end of line");
}
}
/*
* Check for `,'.
*/
comma()
{
if(getnb() != ',')
err(',',"missing comma");
}